import 'dart:math';

import 'package:flutter/material.dart';
import 'package:top_foundation/utils/util.dart';

class DropDownView extends StatefulWidget {
  const DropDownView({
    super.key,
    required this.sourceKey,
    this.width,
    this.padding,
    this.initialVal,
    this.list,
    this.prefixList,
    this.alignment,
    this.childBuilder,
    this.itemHeight,
    this.unSelectedStyle,
    this.selectedStyle,
    this.prefixSize,
    this.isAlignLeft = true,
  });
  final GlobalKey sourceKey;
  final double? width;
  final EdgeInsets? padding;
  final String? initialVal;
  final List<String>? list;
  final Widget Function(bool isUp)? childBuilder;
  final List? prefixList;
  final MainAxisAlignment? alignment;
  final bool isAlignLeft;
  final double? itemHeight;
  final TextStyle? unSelectedStyle;
  final TextStyle? selectedStyle;
  final double? prefixSize;
  @override
  State<DropDownView> createState() => _DropDownViewState();
}

class _DropDownViewState extends State<DropDownView> {
  late EdgeInsets frame;
  late ScrollController sc;
  late double itemHeight;
  late final TextStyle unSelectedStyle;
  late final TextStyle selectedStyle;
  late final double prefixSize;
  late final int curr;

  void getDialogFrame(
    GlobalKey key, {
    double? width,
  }) {
    var robj = key.currentContext?.findRenderObject() as RenderBox?;
    if (robj == null) {
      frame = EdgeInsets.zero;
      return;
    }
    var w = width ?? robj.size.width;

    var offset = robj.localToGlobal(Offset(0, robj.size.height));

    var left = offset.dx - (widget.padding?.left ?? 0);
    if (left < 12.r) {
      left = max(0, min(left, 1.sw - w));
    }
    if (!widget.isAlignLeft) {
      left = left + robj.size.width - w;
    }

    var top = offset.dy + (widget.padding?.top ?? 0);
    var bottom = 0.0;
    if (offset.dy > 1.sh / 3 * 2) {
      bottom = 1.sh - top + robj.size.height;
      top = 0;
    }
    frame = EdgeInsets.fromLTRB(left, top, w, bottom);
  }

  void setupInitialization() {
    if (widget.list != null) {
      var index =
          widget.list!.indexWhere((element) => element == widget.initialVal);
      double initScrollOffset = 0;
      if (index > 0 && index < widget.list!.length) {
        initScrollOffset =
            itemHeight * min(index, max(widget.list!.length - 5, 0));
      }

      sc = ScrollController(initialScrollOffset: initScrollOffset);
    }
  }

  Widget _getPrefix(int i, bool isSelected) {
    final x = widget.prefixList![i];
    if (x is Widget) {
      return x;
    }
    if (x is String) {
      return loadImage(
        url: x,
        width: 14.r,
        height: 14.r,
        fit: BoxFit.contain,
        color: isSelected ? selectedStyle.color : unSelectedStyle.color,
      );
    }
    if (x is IconData) {
      return Icon(
        x,
        size: 14.r,
        color: isSelected ? selectedStyle.color : unSelectedStyle.color,
      );
    }
    return const SizedBox();
  }

  @override
  void initState() {
    itemHeight = widget.itemHeight ?? 40.r;
    unSelectedStyle =
        TextStyle(color: const Color(0xff333333), fontSize: 13.sp);
    selectedStyle = TextStyle(color: const Color(0xff004DB6), fontSize: 13.sp);
    prefixSize = 14.r;
    getDialogFrame(widget.sourceKey, width: widget.width);
    setupInitialization();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    var list = widget.list;

    return GestureDetector(
      onTap: Get.back,
      behavior: HitTestBehavior.opaque,
      child: Column(
        // crossAxisAlignment: CrossAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.start,
        verticalDirection:
            frame.top == 0 ? VerticalDirection.up : VerticalDirection.down,
        children: [
          GestureDetector(
            // onTap: Get.back,
            child: Container(
              height: frame.top,
              color: Colors.transparent,
            ),
          ),
          if (widget.childBuilder != null)
            Container(
              margin: EdgeInsets.only(bottom: frame.bottom, left: frame.left),
              width: frame.right,
              constraints: BoxConstraints(
                maxHeight: 0.7.sh,
                minHeight: 50.r,
              ),
              decoration: BoxDecoration(
                color: Colors.transparent,
                borderRadius: BorderRadius.circular(4.r),
              ),
              child: widget.childBuilder!(frame.top > 0),
            )
          else if (list != null)
            Container(
              margin: EdgeInsets.only(bottom: frame.bottom, left: frame.left),
              width: frame.right,
              constraints: BoxConstraints(
                maxHeight: 250.r,
                minHeight: 50.r,
              ),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(20.r),
              ),
              child: Card(
                margin: EdgeInsets.zero,
                child: ListView(
                  padding: EdgeInsets.zero,
                  shrinkWrap: true,
                  controller: sc,
                  reverse: frame.top != 0,
                  children: list
                      .asMap()
                      .map(
                        (key, e) => MapEntry(
                          key,
                          GestureDetector(
                            onTap: () {
                              Get.back(result: key);
                            },
                            child: Container(
                              padding: EdgeInsets.symmetric(
                                  horizontal: 12.r, vertical: 10.r),
                              // height: 50.r,
                              constraints: BoxConstraints(minHeight: 50.r),
                              decoration: UnderlineTabIndicator(
                                  insets:
                                      EdgeInsets.symmetric(horizontal: 12.r),
                                  borderSide: const BorderSide(
                                      width: 1, color: Color(0xffeeeeee))),
                              child: SeparatorRow(
                                mainAxisAlignment:
                                    widget.alignment ?? MainAxisAlignment.start,
                                children: [
                                  if (key < (widget.prefixList?.length ?? 0))
                                    _getPrefix(key, widget.initialVal == e),
                                  Flexible(
                                    child: Text(
                                      e,
                                      style: widget.initialVal == e
                                          ? selectedStyle
                                          : unSelectedStyle,
                                    ),
                                  )
                                ],
                                separatorBuilder: (index) => const SizedBox(
                                  width: 10,
                                ),
                              ),
                            ),
                          ),
                        ),
                      )
                      .values
                      .toList(),
                ),
              ),
            ),
          Expanded(
            child: GestureDetector(
              onTap: Get.back,
              child: Container(
                color:
                    frame.right >= 1.sw ? Colors.black45 : Colors.transparent,
              ),
            ),
          )
        ],
      ),
    );
  }
}

class DropDownOptionView extends StatefulWidget {
  const DropDownOptionView({
    super.key,
    required this.sourceKey,
    required this.list,
    required this.onChanged,
    this.mutilable = true,
    this.selected,
    this.width,
    this.right,
    this.bgColor,
  });
  final GlobalKey sourceKey;
  final bool mutilable;
  final List<int>? selected;
  final List<String> list;
  final void Function(List<int> all) onChanged;
  final double? width;
  final double? right;
  final Color? bgColor;
  @override
  State<DropDownOptionView> createState() => _DropDownOptionViewState();
}

class _DropDownOptionViewState extends State<DropDownOptionView> {
  late List<int> selected;
  Color? bgColor;
  late final itemHeight = 50.r;
  @override
  void initState() {
    selected = widget.selected ?? [];
    bgColor = widget.bgColor ?? const Color(0xffF1F0FF);
    super.initState();
  }

  Widget _child(bool isUp) {
    return Stack(
      children: [
        Positioned(
          top: isUp ? 0 : null,
          bottom: isUp ? null : 0,
          right: 56.r,
          child: ArrowVerticalView(
            height: 18.r,
            color: bgColor,
            isUp: isUp,
          ),
        ),
        Container(
          decoration: BoxDecoration(
            color: bgColor,
            borderRadius: BorderRadius.circular(14.r),
          ),
          constraints: BoxConstraints(
              maxHeight: itemHeight * min(5, widget.list.length) + 20.r),
          margin:
              EdgeInsets.only(top: isUp ? 18.r : 0, bottom: isUp ? 0 : 18.r),
          child: MediaQuery.removePadding(
            context: context,
            removeBottom: true,
            removeTop: true,
            child: ListView.builder(
                reverse: !isUp,
                padding: EdgeInsets.symmetric(vertical: 10.r),
                itemBuilder: (context, index) {
                  final text = widget.list[index];
                  return _OptionCell(
                    text: text,
                    selected: selected.contains(index),
                    onTap: () {
                      if (selected.contains(index)) {
                        selected.remove(index);
                      } else {
                        if (widget.mutilable) {
                          selected.add(index);
                        } else {
                          selected = [index];
                        }
                      }
                      setState(() {});

                      widget.onChanged(selected);
                    },
                    height: itemHeight,
                  );
                },
                itemCount: widget.list.length),
          ),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return DropDownView(
      sourceKey: widget.sourceKey,
      width: widget.width,
      isAlignLeft: false,
      childBuilder: _child,
    );
  }
}

class _OptionCell extends StatelessWidget {
  const _OptionCell({
    required this.text,
    this.selected = false,
    required this.onTap,
    required this.height,
  });
  final String text;
  final bool selected;
  final VoidCallback onTap;
  final double height;
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: Container(
        padding: EdgeInsets.fromLTRB(19.r, 0, 26.r, 0),
        height: height,
        alignment: Alignment.centerLeft,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              text,
              style: TextStyle(color: const Color(0xff333333), fontSize: 14.sp),
            ),
            Icon(
              Icons.check_circle,
              color:
                  selected ? const Color(0xff7774FC) : const Color(0xffD6D6D6),
            ),
          ],
        ),
      ),
    );
  }
}

class ArrowVerticalView extends StatelessWidget {
  const ArrowVerticalView({
    super.key,
    required this.height,
    this.color,
    required this.isUp,
  });
  final double height;
  final Color? color;
  final bool isUp;
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: height * sqrt(2),
      height: height,
      child: CustomPaint(
        painter: isUp
            ? ArrowUpPainter(fillColor: color)
            : ArrowDownPainter(fillColor: color),
      ),
    );
  }
}

class ArrowUpPainter extends CustomPainter {
  ArrowUpPainter({this.fillColor});
  final Color? fillColor;
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = fillColor ?? Colors.white
      ..strokeWidth = 2
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = 10.r;
    final p = Path()
      ..moveTo(0, size.height)
      ..lineTo(size.width, size.height)
      ..lineTo(size.width / 2 + radius / 2, radius)
      ..quadraticBezierTo(
          size.width / 2, 0, size.width / 2 - radius / 2, radius);

    canvas.drawPath(p, paint);
  }

  @override
  bool shouldRepaint(ArrowUpPainter oldDelegate) => false;

  @override
  bool shouldRebuildSemantics(ArrowUpPainter oldDelegate) => false;
}

class ArrowDownPainter extends CustomPainter {
  ArrowDownPainter({this.fillColor});
  final Color? fillColor;
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = fillColor ?? Colors.white
      ..strokeWidth = 2
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
    final radius = 10.r;
    final p = Path()
      ..moveTo(0, 0)
      ..lineTo(size.width, 0)
      ..lineTo(size.width / 2 + radius / 2, size.height - radius)
      ..quadraticBezierTo(size.width / 2, size.height,
          size.width / 2 - radius / 2, size.height - radius);

    canvas.drawPath(p, paint);
  }

  @override
  bool shouldRepaint(ArrowDownPainter oldDelegate) => false;

  @override
  bool shouldRebuildSemantics(ArrowDownPainter oldDelegate) => false;
}
